package com.lagou.edu.utils;

import com.alibaba.druid.util.StringUtils;
import com.lagou.edu.SpringConfig;
import com.lagou.edu.annotation.Autowired;
import com.lagou.edu.annotation.Service;
import com.lagou.edu.dao.AccountDao;
import com.lagou.edu.service.impl.TransferServiceImpl;
import org.reflections.Reflections;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import javax.sql.DataSource;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;

/**
 * @author huangshuxian
 * @date 2022/1/22 4:51 下午
 * @description
 */
public class LagouApplicationContext {

    public static Map<String, Object> map = new HashMap<>();

    static{
        //1、扫描对应包，通过反射实例化对象
        try{
            //扫描包
            Reflections reflections = new Reflections("com.lagou.edu");
            //获取加了Service注解的类集合
            Set<Class<?>> serviceTypesAnnotatedWith = reflections.getTypesAnnotatedWith(Service.class);
            for (Class<?> c : serviceTypesAnnotatedWith) {
                System.out.println("[LagouApplicationContext]实例化bean" + c);
                //通过反射实例化对象
                Object bean = c.newInstance();
                Service annotation = c.getAnnotation(Service.class);
                //判断是否有value值
                if (StringUtils.isEmpty(annotation.value())){
                    //没有值用类名
                    String[] split = c.getName().split("\\.");
                    System.out.println("split" + split);
                    map.put(split[split.length - 1], bean);
                }else{
                    map.put(annotation.value(), bean);
                }
            }

            //注入dataSource
            ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfig.class);

            DataSource dataSource = (DataSource) applicationContext.getBean("DataSource");

            map.put("DataSource", dataSource);


            //获取加了@Bean的方法
//            Set<Method> methodsAnnotatedWith = reflections.getMethodsAnnotatedWith(Bean.class);
//            for (Method method : methodsAnnotatedWith) {
//                //通过反射创建bean
//                Object invoke = method.invoke(new SpringConfig());
//                Bean annotation = method.getAnnotation(Bean.class);
//                //判断是否有value值
//                if (StringUtils.isEmpty(annotation.value())){
//                    //没有值用类名
//                    String[] split = method.getName().split("\\.");
//                    System.out.println("split" + split);
//                    map.put(split[split.length - 1], invoke);
//                }else{
//                    map.put(annotation.value(), invoke);
//                }
//            }


            //遍历对象，解析Autowired
            for (Map.Entry<String, Object> entry : map.entrySet()) {
                Object o = entry.getValue();
                //获取所有变量
                Field[] fields = o.getClass().getDeclaredFields();
                for (Field field : fields) {
                    //判读是否使用Autowired注解
                    if (field.isAnnotationPresent(Autowired.class) && field.getAnnotation(Autowired.class).required()){
                        //获取该属性的名称
                        String[] names = field.getType().getName().split("\\.");
                        String name = names[names.length - 1];
                        System.out.println("[LagouApplicationContext]依赖注入" + name);
                        //通过getMethods找到set方法
                        Optional<Method> first = Arrays.stream(o.getClass().getMethods()).filter(m -> ("set" + name).equalsIgnoreCase(m.getName())).findFirst();
                        if (first.isPresent()){
                            System.out.println("set" + first.get());
                            //通过invoke调用set方法
                            //todo: map.get(name)能否取到要注入的bean
                            //注意获取到name是首字母大写
                            first.get().invoke(o, map.get(name));
                        }
                    }
                }
            }

        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }

        System.out.println(((TransferServiceImpl)map.get("transferService")).accountDao);
    }

    public Object getBean(String name){
        return map.get(name);
    }
}
